﻿using System.Collections.Generic;
using System.Windows.Input;

namespace Red.Controls
{
    internal class AutoCompletion
    {
        #region Data

        private int _nextCmdIndex;
        private bool _recreatePossibleCommandsSet;
        private string[] _availableCommands;
        private string[] _possibleCommands;
        private int _textBaseIndex;
        private int _userCursor;
        private string _constantText;

        #endregion

        #region Properties

        /// <summary>
        /// All available commands
        /// </summary>
        public string[] AvailableCommands
        {
            get { return _availableCommands; }
            set
            {
                _availableCommands = value;
                PossibleCommands = _availableCommands;
            }
        }

        /// <summary>
        /// All commands which are adjusted to part of command in terminal
        /// </summary>
        public string[] PossibleCommands
        {
            get { return _possibleCommands; }
            set
            {
                _possibleCommands = value;
                _nextCmdIndex = -1;
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Default constructor
        /// </summary>
        public AutoCompletion()
        {
            _nextCmdIndex = -1;
            _recreatePossibleCommandsSet = true;
            _constantText = "";
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Find the best match command for current line
        /// </summary>
        /// <param name="currentLine">Current line from terminal</param>
        /// <returns>Complemented line</returns>
        public string Replace( string currentLine )
        {
            CreatePossibleCommandsCollection( currentLine );

            if ( PossibleCommands != null && PossibleCommands.Length != 0 )
            {
                if ( Keyboard.Modifiers == ModifierKeys.Shift )
                {
                    --_nextCmdIndex;
                    if ( _nextCmdIndex < 0 )
                        _nextCmdIndex = PossibleCommands.Length - 1;
                }
                else
                {
                    ++_nextCmdIndex;
                    if ( _nextCmdIndex >= PossibleCommands.Length )
                        _nextCmdIndex = 0;
                }

                return _constantText + PossibleCommands[_nextCmdIndex];
            }

            return currentLine;
        }

        /// <summary>
        /// Forces create new collection with possible commands
        /// </summary>
        public void RecreatePossibleCommands()
        {
            _recreatePossibleCommandsSet = true;
        }

        /// <summary>
        /// Stores information about base text in terminal
        /// </summary>
        /// <param name="textBaseIndex">Cursor position after base text</param>
        public void SetTextBase( int textBaseIndex )
        {
            _textBaseIndex = textBaseIndex;
            _userCursor = textBaseIndex;
            _constantText = "";
        }

        /// <summary>
        /// Stores information about text cursor position
        /// </summary>
        /// <param name="userCursor"></param>
        public void SetUserCursor( int userCursor )
        {
            _userCursor = userCursor;
        }

        #endregion

        #region Private Methods

        private void CreatePossibleCommandsCollection( string currentLine )
        {
            if ( _recreatePossibleCommandsSet == true )
            {
                if ( _userCursor != _textBaseIndex )
                {
                    var textBase = currentLine.Substring( _textBaseIndex );
                    var lastSpaceIndex = textBase.LastIndexOf( ' ' );
                    var partOfCommandName = ( lastSpaceIndex == -1 ) ? textBase : textBase.Substring( lastSpaceIndex );
                    _constantText = ( lastSpaceIndex == -1 || lastSpaceIndex == 0 ) ? "" : textBase.Substring( 0, lastSpaceIndex + 1 );

                    CreatePossibleCommands( partOfCommandName.Trim() );
                }
            }
        }

        private void CreatePossibleCommands( string partOfCommandName )
        {
            var listOfPossibleCommands = new List<string>();
            foreach ( var cmd in AvailableCommands )
            {
                if ( cmd.StartsWith( partOfCommandName ) )
                {
                    listOfPossibleCommands.Add( cmd );
                }
            }
            PossibleCommands = listOfPossibleCommands.ToArray();

            _recreatePossibleCommandsSet = false;
            _nextCmdIndex = -1;
        }

        #endregion
    }
}
